package com.castle.fortress.admin.utils;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.castle.fortress.admin.study.course.entity.StudyCoursewareEntity;
import com.castle.fortress.admin.study.course.mapper.StudyCoursewareMapper;
import com.castle.fortress.admin.system.dto.ConfigApiDto;
import com.castle.fortress.admin.system.service.ConfigApiService;
import com.castle.fortress.admin.system.service.OssService;
import com.castle.fortress.common.entity.RespBody;
import com.itextpdf.text.pdf.PdfReader;
import org.apache.http.entity.ContentType;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.*;

/**
 * 依赖libreoffice实现PDF转化
 *
 * @author Dawn
 */
@Component
public class PdfUtils {
    @Autowired
    private StudyCoursewareMapper studyCoursewareMapper;
    @Autowired
    private OssService ossService;
    @Autowired
    private ConfigApiService configApiService;


    private boolean taskRun;
    private int maxTaskNum = 3;
    private ConcurrentLinkedQueue<Callable<Boolean>> concurrentLinkedQueue = new ConcurrentLinkedQueue<>();


    public void taskRun() {
        taskRun = true;
        int runTaskNumber = Math.min(maxTaskNum, concurrentLinkedQueue.size());
        for (int i = 0; i < runTaskNumber; i++) {
            new Thread(() -> {
                while (true) {
                    Callable<Boolean> poll = concurrentLinkedQueue.poll();
                    Boolean call = null;
                    try {
                        if (poll == null) {
                            taskRun = false;
                            System.out.println("所有的任务全部处理完成");
                            break;
                        }
                        call = poll.call();
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                    System.out.println("正在处理中......." + Thread.currentThread().getName() + ",还剩下" + concurrentLinkedQueue.size() + "任务需要处理" + call);
                }
            }, "pdfTask" + i).start();
        }

    }

    public int getQueueSize(){
        return concurrentLinkedQueue.size();
    }
    public void taskAdd(String fileUrl, String coursewareName, Long coursewareId) {
        concurrentLinkedQueue.add(() -> {
            try {
                toPdf(fileUrl, coursewareName, coursewareId);
            } catch (Exception e) {
                e.printStackTrace();
//                throw new RuntimeException(e);
            }
            return true;
        });
        System.out.println("添加任务成功，" + coursewareName + " 有" + concurrentLinkedQueue.size() + "任务需要处理");
    }

    public void taskPngAdd(String PdfFilePath,  int dpi, Long coursewareId, String coursewareName) {
        concurrentLinkedQueue.add(() -> {
            try {
                ConfigApiDto configApiDto = configApiService.getByBindCode("STUDY");
                if (configApiDto == null || StrUtil.isEmpty(configApiDto.getBindDetail())) {
                    System.err.println(configApiDto);
                    System.err.println("未配置pdf转图片本地路径");
                }else {
                    JSONObject config = JSONUtil.parseObj(configApiDto.getBindDetail());
                    String localPath = config.getStr("localPath");
                    pdf2Image(PdfFilePath,localPath,dpi,coursewareId,coursewareName);
                }

            } catch (Exception e) {
                e.printStackTrace();
//                throw new RuntimeException(e);
            }
            return true;
        });
        System.out.println("添加任务成功，" + coursewareName + " 有" + concurrentLinkedQueue.size() + "任务需要处理");
    }
    /**
     * 文件转pdf  文档:https://www.yuque.com/hcwdc/open/pos2lih1vi3248g9
     *
     * @param fileUrl        网络路径 非pdf文件
     * @param coursewareName
     */
    public void toPdf(String fileUrl, String coursewareName, Long coursewareId) {
        // todo 先存到本地  然后转成pdf 再把pdf上传获取连接  把这个连接保存
        ConfigApiDto configApiDto = configApiService.getByBindCode("STUDY");
        if (configApiDto == null || StrUtil.isEmpty(configApiDto.getBindDetail())) {
            System.err.println(configApiDto);
            System.err.println("未配置pdf转图片本地路径");
            return;
        }
        JSONObject config = JSONUtil.parseObj(configApiDto.getBindDetail());
        String localPath = config.getStr("localPath");
        if (StrUtil.isEmpty(localPath)) {
            System.err.println("未配置pdf转图片本地路径");
            return;
        }
        int dot = fileUrl.lastIndexOf('.');
        int lastSep = fileUrl.lastIndexOf("/") + 1;
        String imagePDFName = fileUrl.substring(lastSep, dot); // 获取文件名
        String suffix = fileUrl.substring(fileUrl.lastIndexOf("."));
        String path = localPath + "/" + imagePDFName + suffix;
        String pdfPath = localPath + "/" + imagePDFName + ".pdf";
        saveToFile(fileUrl, path);
        long start = System.currentTimeMillis();
        System.out.println("源文件：" + path);
        System.out.println("目标文件" + localPath);
        String command = "";
        String osName = System.getProperty("os.name");
        System.out.println("系统名称：" + osName);
        boolean isSuccess = true;
        if (osName.contains("Windows")) {
            command = "soffice --headless --convert-to pdf " + path + " --outdir " + localPath;
            isSuccess = windowExec(command);
            System.err.println("执行结果:" + isSuccess);
        } else {
            command = "libreoffice7.0 --convert-to pdf:writer_pdf_Export " + path + " --outdir " + localPath;
            LinuxExec(command);
        }
        long end = System.currentTimeMillis();
        System.err.println("执行了命令:" + command);
        System.out.println("转换文件耗时：" + (end - start) + "毫秒");
        if (isSuccess) {

            File dstFile = new File(pdfPath);
            FileInputStream inputStream = null;
            try {
                inputStream = new FileInputStream(dstFile);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            MultipartFile multipartFile = null;
            try {
                multipartFile = new MockMultipartFile(dstFile.getName(), dstFile.getName(),
                        ContentType.APPLICATION_OCTET_STREAM.toString(), inputStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
            RespBody uploadRespBody = ossService.putFile(multipartFile);
            System.err.println("保存生成的png图片返回:" + uploadRespBody);
            JSONArray jsonArray = new JSONArray();
            JSONObject jsonObject = new JSONObject();
            jsonObject.set("url", JSONUtil.parseObj(uploadRespBody.getData()).getStr("url"));
            jsonObject.set("name", imagePDFName);
            jsonObject.set("coursewareName", coursewareName);
            // todo
            jsonArray.add(jsonObject);
            StudyCoursewareEntity entity = new StudyCoursewareEntity();
            entity.setId(coursewareId);
            entity.setCoursewareUrl(jsonArray.toString());
            entity.setNeedConver(1);
            studyCoursewareMapper.updateById(entity);
            String url = JSONUtil.parseArray(entity.getCoursewareUrl()).getJSONObject(0).getStr("url");
             pdf2Image(url,localPath,96,entity.getId(),coursewareName);
        }
    }
    public boolean isTaskRunning() {
        return this.taskRun;
    }
    /**
     * 获取网络路径的目标文件夹
     *
     * @param fileUrl
     * @return
     */
    public String getTargetFolder(String fileUrl) {
        String prefix = "http://";
        int index = fileUrl.indexOf(prefix) + prefix.length();
        String suffix = fileUrl.substring(fileUrl.lastIndexOf("."));
        int end = fileUrl.lastIndexOf("/") + 1;
        String targetUrl = LocalPath + fileUrl.substring(index, end);
        return targetUrl;
    }

    //    public static String LocalPath = "/www/wwwroot/";
    public static String LocalPath = "C:\\Users\\86159\\Desktop\\test";

    /**
     * 获取网络路劲的服务器本地路径
     *
     * @param fileUrl
     * @return
     */
    public String getLocalPath(String fileUrl) {
        String prefix = "http://";
        if (fileUrl.indexOf(prefix) == -1) {
            prefix = "https://";
        }
        int index = fileUrl.indexOf(prefix) + prefix.length();
        String localPath = LocalPath + fileUrl.substring(index);
        return localPath;
    }

    public static String fileName(String fileUrl) {
        int dotIndex = fileUrl.lastIndexOf(".");
        int lastSeparator = fileUrl.lastIndexOf(File.separator);
        if (lastSeparator == -1) {
            return fileUrl.substring(0, dotIndex);
        } else {
            return fileUrl.substring(lastSeparator + 1, dotIndex);
        }
    }

    private boolean windowExec(String command) {
        Process process;// Process可以控制该子进程的执行或获取该子进程的信息
        try {
            process = Runtime.getRuntime().exec(command);// exec()方法指示Java虚拟机创建一个子进程执行指定的可执行程序，并返回与该子进程对应的Process对象实例。
            // 下面两个可以获取输入输出流
            InputStream errorStream = process.getErrorStream();
            InputStream inputStream = process.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }

        int exitStatus = 0;
        try {
            exitStatus = process.waitFor();// 等待子进程完成再往下执行，返回值是子线程执行完毕的返回值,返回0表示正常结束
            // 第二种接受返回值的方法
            int i = process.exitValue(); // 接收执行完毕的返回值
        } catch (InterruptedException e) {
            e.printStackTrace();
            return false;
        }
        process.destroy(); // 销毁子进程
        process = null;
        return true;
    }

    private void LinuxExec(String cmd) {
        System.out.println(cmd);
        try {
            Runtime.getRuntime().exec(cmd);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /***
     * PDF文件转PNG图片，全部页数
     *
     * @param PdfFilePath pdf完整路径 url路径
     * @param dstImgFolder 图片存放的文件夹
     * @param dpi dpi越大转换后越清晰，相对转换速度越慢 dpi为96,100,105,120,150,200中,105显示效果较为清晰,体积稳定,dpi越高图片体积越大,一般电脑显示分辨率为96
     * @param coursewareName
     * @return
     */
//    @Async
    public Integer pdf2Image(String PdfFilePath, String dstImgFolder, int dpi, Long coursewareId, String coursewareName) {
        StudyCoursewareEntity entity = new StudyCoursewareEntity();
        entity.setPdfImageNum(0);
        entity.setNeedConver(2);//转化中
        entity.setId(coursewareId);
        studyCoursewareMapper.updatePngNum(entity);

        int pages = 1;
        URL urlfile;
        PDDocument pdDocument;
        InputStream inStream = null;
        try {
            //服务器下载
            urlfile = new URL(PdfFilePath);
            inStream = urlfile.openStream();
//            File file = new File(PdfFilePath);
//            pdDocument = PDDocument.load(file);
            int dot = PdfFilePath.lastIndexOf('.');
            int lastSep = PdfFilePath.lastIndexOf("/") + 1;
            String imagePDFName = PdfFilePath.substring(lastSep, dot); // 获取图片文件名

            pdDocument = PDDocument.load(inStream);
            PDFRenderer renderer = new PDFRenderer(pdDocument);
            /* dpi越大转换后越清晰，相对转换速度越慢 */
            PdfReader reader = new PdfReader(PdfFilePath);
            pages = reader.getNumberOfPages();
            StringBuffer imgFilePath = null;
            JSONArray jsonArray = new JSONArray();

            for (int i = 0; i < pages; i++) {
                JSONObject jsonObject = new JSONObject();
                jsonObject.set("name", imagePDFName);
                String imgFilePathPrefix = dstImgFolder + File.separator + imagePDFName;
//                String imgFilePathPrefix = "C:\\Users\\86159\\Desktop\\test\\"+ imagePDFName;
                imgFilePath = new StringBuffer();
                imgFilePath.append(imgFilePathPrefix);
                imgFilePath.append("_");
                imgFilePath.append(String.valueOf(i + 1));
                imgFilePath.append(".png");
                File dstFile = new File(imgFilePath.toString());
                BufferedImage image = renderer.renderImageWithDPI(i, dpi);
                ImageIO.write(image, "png", dstFile);
                FileInputStream inputStream = new FileInputStream(dstFile);
                MultipartFile multipartFile = new MockMultipartFile(dstFile.getName(), dstFile.getName(),
                        ContentType.APPLICATION_OCTET_STREAM.toString(), inputStream);
                RespBody uploadRespBody = ossService.putFile(multipartFile);
                System.err.println("保存生成的png图片返回:" + uploadRespBody);
                jsonObject.set("url", JSONUtil.parseObj(uploadRespBody.getData()).getStr("url"));
                jsonObject.set("coursewareName",coursewareName);
                jsonArray.add(jsonObject);
            }
            System.out.println("PDF文档转PNG图片成功！");
            entity.setCoursewareUrl(jsonArray.toString());
            entity.setPdfImageNum(pages);
            entity.setNeedConver(0);//已转化
            studyCoursewareMapper.updatePngNum(entity);
            System.out.println(entity.getId() + "-" + entity.getCoursewareName() + ":已更新");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return pages;
    }

//    public static void main(String[] args) {
//        String url = "http://cpb.hcses.cn/uploads/20201215/363c0bbf8f1f4ba29a8944e90a6ba0d1.pdf";
//        System.out.println(new PdfUtils().getTargetFolder(url));
//        System.out.println(new PdfUtils().getLocalPath(url));
////        System.out.println(fileName("E:\\hcsesProject\\cpb\\admin\\renren-admin\\target\\f84430740efc471bb073294b6f6a6336.pdf"));
//    }

    // url: 链接,可访问的图片,视频,或其他文件
    public MultipartFile urlTransferMultipartFile(String url) {
        //对本地文件命名,可以从链接截取,可以自己手写,看需求
//        String fileName = "img_test";
        String fileName = url.substring(url.lastIndexOf("."));
        File file = null;
        URL urlfile;
        InputStream inStream = null;
        OutputStream os = null;
        MultipartFile multipartFile = null;
        try {
            file = File.createTempFile("net_url", fileName);
            //下载
            urlfile = new URL(url);
            inStream = urlfile.openStream();
            os = new FileOutputStream(file);

            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            while ((bytesRead = inStream.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            // file转multipartFile,如果只需要转File就不用加下面这两行代码,直接返回File即可
            FileInputStream inputStream = new FileInputStream(file);
            multipartFile = new MockMultipartFile(file.getName(), file.getName(),
                    ContentType.APPLICATION_OCTET_STREAM.toString(), inputStream);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != os) {
                    os.close();
                }
                if (null != inStream) {
                    inStream.close();
                }
                // 用完删除
                if (null != file) {
                    file.delete();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        // 按需返回file还是multipartFile
        return multipartFile;
    }

    /**
     * 文件保存到本地指定路径
     *
     * @param fileUrl
     * @param saveDir
     * @return
     */
    public static String saveToFile(String fileUrl, String saveDir) {
        FileOutputStream fos = null;
        BufferedInputStream bis = null;
        HttpURLConnection httpUrl = null;
        URL url = null;
        byte[] buf = new byte[1024];
        int size = 0;

        try {
            //这里填入下载的URL
            url = new URL(fileUrl);
            httpUrl = (HttpURLConnection) url.openConnection();
            httpUrl.connect();
            bis = new BufferedInputStream(httpUrl.getInputStream());
            fos = new FileOutputStream(saveDir);
            while ((size = bis.read(buf)) != -1) {
                fos.write(buf, 0, size);
            }
            //记得及时释放资源
            fos.close();
            bis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        httpUrl.disconnect();
        return null;
    }

    public static void main(String[] args) {
        saveToFile("https://hcses-1251334741.cos.ap-nanjing.myqcloud.com/v2test/20230724/1690181863607.doc", "D:\\PDF2IMG\\1.doc");
    }
}
